/******************************************************************************
 * Copyright (C) 2008 Adam Parker. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ******************************************************************************/
 
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;

public class EditableHeader extends JTableHeader implements CellEditorListener 
{
	public final int HEADER_ROW = -10;
	transient protected int editingColumn;
	transient protected TableCellEditor cellEditor;
	transient protected Component editorComp;

	public EditableHeader(TableColumnModel columnModel)
	{
		super(columnModel);
		setReorderingAllowed(false);
		cellEditor = null;
		recreateTableColumn(columnModel);
	}
  
	public void updateUI()
	{
		setUI(new EditableHeaderUI());
		resizeAndRepaint();
		invalidate();
	}
  
	protected void recreateTableColumn(TableColumnModel columnModel)
	{
		int n = columnModel.getColumnCount();
		EditableHeaderTableColumn[] newCols = new EditableHeaderTableColumn[n];
		TableColumn[] oldCols = new TableColumn[n];
		for (int i=0;i<n;i++) 
		{
			oldCols[i] = columnModel.getColumn(i);
			newCols[i] = new EditableHeaderTableColumn();
			newCols[i].copyValues(oldCols[i]);
		}
		for (int i=0;i<n;i++)
		{
			columnModel.removeColumn(oldCols[i]);
		}
		for (int i=0;i<n;i++) 
		{
			columnModel.addColumn(newCols[i]);
		}
	}

	public boolean editCellAt(int index)
	{
		return editCellAt(index);
	}
  
	public boolean editCellAt(int index, EventObject e)
	{
		if (cellEditor != null && !cellEditor.stopCellEditing())
		{ 
			return false;
		}
		if (!isCellEditable(index))
		{
			return false;
		}    
		TableCellEditor editor = getCellEditor(index);
    
		if (editor != null && editor.isCellEditable(e))
		{
			editorComp = prepareEditor(editor, index);
			editorComp.setBounds(getHeaderRect(index));
			add(editorComp);
			editorComp.validate();
			setCellEditor(editor);
			setEditingColumn(index);
			editor.addCellEditorListener(this);
			return true;
		}    
		return false;
	}
  
	public boolean isCellEditable(int index)
	{
		if (getReorderingAllowed())
		{
			return false;
		}
		int columnIndex = columnModel.getColumn(index).getModelIndex();
		EditableHeaderTableColumn col = (EditableHeaderTableColumn)columnModel.getColumn(columnIndex);
		return col.isHeaderEditable();
	}
  
	public TableCellEditor getCellEditor(int index)
	{
		int columnIndex = columnModel.getColumn(index).getModelIndex();
		EditableHeaderTableColumn col = (EditableHeaderTableColumn)columnModel.getColumn(columnIndex);
		return col.getHeaderEditor();
	}
  
	public void setCellEditor(TableCellEditor newEditor)
	{
	    TableCellEditor oldEditor = cellEditor;
	    cellEditor = newEditor;
    
		// firePropertyChange
    
	    if (oldEditor != null && oldEditor instanceof TableCellEditor)
		{
			((TableCellEditor)oldEditor).removeCellEditorListener((CellEditorListener)this);
	    }
	    if (newEditor != null && newEditor instanceof TableCellEditor)
		{
			((TableCellEditor)newEditor).addCellEditorListener((CellEditorListener)this);
	    }
	}

	public Component prepareEditor(TableCellEditor editor, int index) 
	{
		Object value = columnModel.getColumn(index).getHeaderValue();
		boolean isSelected = true;
		int            row = HEADER_ROW;
		JTable       table = getTable();
		Component comp = editor.getTableCellEditorComponent(table, value, isSelected, row, index);
		if (comp instanceof JComponent)
		{ 
			((JComponent)comp).setNextFocusableComponent(this);             
		}
		return comp;
	}
  
	public TableCellEditor getCellEditor() 
	{
		return cellEditor;
	}
  
	public Component getEditorComponent()
	{
		return editorComp;
	}
  
	public void setEditingColumn(int aColumn)
	{
		editingColumn = aColumn;
	}
  
	public int getEditingColumn() 
	{
		return editingColumn;
	}
  
	public void removeEditor()
	{
		TableCellEditor editor = getCellEditor();
		if (editor != null) 
		{
			editor.removeCellEditorListener(this);

			requestFocus();
			remove(editorComp);

			int index = getEditingColumn();
			Rectangle cellRect = getHeaderRect(index);

			setCellEditor(null);
			setEditingColumn(-1);
			editorComp = null;

			repaint(cellRect);
		}
	}
  
	public boolean isEditing() 
	{
		return (cellEditor == null)? false : true;
	}

  //
  // CellEditorListener
  //
	public void editingStopped(ChangeEvent e) 
	{
		TableCellEditor editor = getCellEditor();
		if (editor != null)
		{
			Object value = editor.getCellEditorValue();
			int index = getEditingColumn();
			columnModel.getColumn(index).setHeaderValue(value);
			removeEditor();
		}
	}

	public void editingCanceled(ChangeEvent e) 
	{
		removeEditor();
	}
  //
  // public void setReorderingAllowed(boolean b) {
  //   reorderingAllowed = false;
  // }
}